/*
 * @Author: xiaohao
 * @Date: 2025-11-03 09:08:19
 * @LastEditors: xiaohao
 * @LastEditTime: 2025-11-05 22:07:58
 * @FilePath: /Project/ConcurrentMemoryPool/src/ThreadCache.cpp
 * @Description:
 */

#include "ConcurrentMemoryPool/ThreadCache.h"
#include "ConcurrentMemoryPool/CentralCache.h"
#include "ConcurrentMemoryPool/ObjectPool.h"

// 获取当前线程的ThreadCache实例
ThreadCache &ThreadCache::GetThreadInstance()
{
    static thread_local ObjectPool<ThreadCache> tcPool;
    static thread_local ThreadCache *instance = nullptr;

    if (instance == nullptr)
    {
        instance = tcPool.New(); // 直接赋值指针
    }
    return *instance; // 解引用返回引用
}

// 申请和释放内存对象
void *ThreadCache::Allocate(size_t size)
{
    // 1. 大小检查
    assert(size > 0);

    // 2. 计算对齐大小和哈希桶索引
    size_t alignSize = SizeClass::RoundUp(size);
    size_t index = SizeClass::Index(alignSize);

    // 3. 检查自由链表
    if (_freeLists[index].Empty() != true)
    {
        return _freeLists[index].Pop();
    }
    else
    {
        // 当自由链表为空时，从中心缓存获取内存
        return FetchFromCentralCache(index, alignSize);
    }
}

void ThreadCache::Deallocate(void *ptr, size_t size)
{
    assert(ptr != nullptr);                // 指针合法性检查
    assert(size > 0 && size <= MAX_BYTES); // 大小合法性检查

    size_t alignSize = SizeClass::RoundUp(size);
    size_t index = SizeClass::Index(alignSize);

    // 将释放的内存块插入对应自由链表（头插法）
    _freeLists[index].Push(ptr);

    // 缓存满时，将内存块归还到中心缓存
    // 当链表长度大于一次批量申请的内存时就开始还一段list给CentralCache
    if (_freeLists[index].Size() >= _freeLists[index].MaxSize())
    {
        ListTooLong(_freeLists[index], size);
    }
}

void ThreadCache::ListTooLong(FreeList &list, size_t size)
{
    void *start = nullptr;
    void *end = nullptr;
    list.PopRange(start, end, list.MaxSize());

    CentralCache &centralcache = CentralCache::GetCentralInstance();
    centralcache.ReleaseListToSpans(start, size);
}

void *ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
    // 从中心缓存中申请内存
    // 慢开始反馈调节算法
    // 1. 最开始不会一次向CentralCache要太多内存, 要太多了可能用不完
    // 2. 如果不断有size内存的需求, 那么 batchNum 就会不断增长, 直到上限[2, 512]
    // 3, size越大, 一次批量向CentralCache获取的数量越少
    // 4. size越小, 一次批量向CentralCache获取的数量越多
    size_t batchNum = std::min(_freeLists[index].MaxSize(), SizeClass::NumMoveSize(size));
    if (_freeLists[index].MaxSize() == batchNum)
    {
        _freeLists[index].MaxSize() += 1;
    }

    void *start = nullptr;
    void *end = nullptr;
    CentralCache &centralCache = CentralCache::GetCentralInstance();
    size_t actualNum = centralCache.FetchRangePbj(start, end, batchNum, size);
    assert(actualNum > 0);

    if (actualNum == 1)
    {
        assert(start == end);
        return start;
    }
    else
    {
        // 将从中心缓存中获取到的内存块插入对应自由链表
        _freeLists[index].PushRange(GetNextObj(start), end, actualNum - 1);
        return start;
    }
}

